/* Proxy(代理) api */
const { log } = console
// 1. 使用代理对目标对象属性进拦截
let f1 = () => {
  let obj = { id: 1, age: 20 }
  // 定义代理对象，对obj进行代理，控制obj对象属性的设置和获取
  let proxy = new Proxy(obj, {
    // 设值器
    set: function (target, key, value, receiver) {
      log(target === obj, key, value, receiver)
      if (key === 'age') {
        if (value <= 0) {
          throw new Error('用户的年龄不能<=0')
        }
      }
      return Reflect.set(target, key, value)
    },
    // 取值器
    get: function (target, key, receiver) {
      log(target === obj, key, receiver)
      return Reflect.get(target, key)
    },
  })
  // 对代理对象进行操作
  proxy.age = proxy.age + 1
  delete proxy.id
  proxy.gender = '女'
  proxy.age = -1
  log(obj)
}

// 代理可以感知对象属性，函数的增、删、改(set函数感知)、获取(get函数感知)

//  2. 对函数进行代理
let f2 = () => {
  let target = function (a, b) {
    return a + b
  }
  // 代理的拦截器
  let handler = {
    // 获得函数
    get(t, k, r) {
      log(t)
      log(k)
      return t.name
    },
    // 拦截调用函数
    apply(t, o, args) {
      log(args)
      return args.reduce((a, b) => a + b)
    },
    // 拦截创建对象
    construct: function (target, args) {
      log(target, args)
      return { value: args }
    },
  }
  let proxy = new Proxy(target, handler)
  // 调用代理函数，实际类似使用目标函数
  // log(proxy(1, 2, 3))
  // 使用代理函数proxy创建对象
  // let p = new proxy(4, 5)
  // log(p)
  // 拦截函数属性获取操作
  log(proxy.name)
}
// f2()

// 3. has(target,key) 拦截 key in proxy操作
let f3 = () => {
  let obj = { a: 1, b: 2 }
  // 判断obj使用有c属性 返回布尔值true/false
  log('c' in obj)
  // 声明拦截器
  let handler = {
    has(target, key) {
      // if (key === 'c') {
      //   return true
      // }
      return key in target
    },
  }
  // 定义代理
  let proxy = new Proxy(obj, handler)
  // 判断proxy是否有c属性
  log('c' in proxy)
}

// 4. 拦截对象属性的删除操作 deleteProperty(t,k)
let f4 = () => {
  // 目标对象
  let t = { _prop: 'foo', id: 1 }
  // 判断私有化属性是否可以删除
  function invariant(propKey, action) {
    propKey[0] === '_' ? action(false) : action(true)
  }
  // 拦截器
  let handler = {
    // 拦截对象属性的删除
    deleteProperty(target, propKey) {
      invariant(propKey, function (res) {
        if (!res) {
          throw new Error(`私有化属性${propKey}不能删除`)
        }
      })
      delete target[propKey]
      return true
    },
  }
  // 定义代理对象
  let proxy = new Proxy(t, handler)
  // delete proxy['_prop']
  // 删除id属性
  let rt = delete proxy['id']
  log(rt)
  log(t)
}

// 5. defineProperty(target, key, descriptor) 拦截属性的定义
let f5 = () => {
  let t = { _prop: 'foo', id: 1 }
  // 拦截器
  let handler = {
    defineProperty(target, key, descriptor) {
      let { value } = descriptor
      target[key] = value
      return true
    },
  }
  let proxy = new Proxy(t, handler)
  proxy.foo = 'bar'
  log(t)
}

// 6. getPrototypeOf(target) 拦截获得对象原型
let f6 = () => {
  let proto = {}
  let t = { _prop: 'foo', id: 1 }
  Object.setPrototypeOf(t, proto)
  // 拦截器
  let handler = {
    getPrototypeOf(target) {
      return proto
    },
  }
  let proxy = new Proxy(t, handler)
  log(proxy.__proto__ === proto) // true
}

// 7. ownKeys(target) 拦截对象属性遍历操作
let f7 = () => {
  let t = { _prop: 'foo', id: 1 }
  // 拦截器
  let handler = {
    ownKeys(target) {
      // _prop这种私有化属性不允许遍历
      let list = Reflect.ownKeys(target)
      let arr = []
      list.forEach((item) => {
        if (item[0] !== '_') {
          arr.push(item)
        }
      })
      return arr
      // return Reflect.ownKeys(target) // 返回对象target的所有属性名称数组
    },
  }
  let proxy = new Proxy(t, handler)
  for (let key in proxy) {
    log(key)
  }
}

// 8. Proxy.revocable(target,handler) 生成一个可取消的代理
let f8 = () => {
  let t = { _prop: 'foo', id: 1 }
  let handler = {}
  let { proxy, revoke } = Proxy.revocable(t, handler)
  proxy.name = 'tom'
  log(t)
  revoke()
  // proxy.gender = '男' // 报错：无法在已经取消的代理对象上设置属性
  log(t)
}
f8()

let f = () => {}
